import copy
import datetime
import traceback

from fastapi import APIRouter
from re_common.baselibrary.tools.all_requests.aiohttp_request import AioHttpRequest
from re_common.baselibrary.tools.myparsel import MParsel
from re_common.baselibrary.utils.basetime import BaseTime
from re_common.baselibrary.utils.core.requests_core import SUCCESS, MsgCode

from apps.allsubdb.cnkijournal.models import SaveHtmlModel, VerificationMongodb, CnkiArticleMongoModel, MongoJsonModel, \
    MongoHtmlModel, SaveJournalIdModel, SaveYearModel, SaveIssueModel, SaveJournalSubjectModel, SaveOutlineModel, \
    SaveOnlineArticleModel
from apps.core.m_route import ContextIncludedRoute
from apps.core.return_info import InputInfoModel, ReturnInfo, FAILED, SaveStepMongoModel, DetailModel
from apps.sql_app.mmongodb import MongoDBClient, Coll

router = APIRouter(route_class=ContextIncludedRoute)


def deal(items, dicts_v=None, is_jsons=False):
    if isinstance(dicts_v, dict):
        dicts = copy.deepcopy(dicts_v)
    else:
        dicts = dicts_v
    # 默认情况下不改变原来mongodb的值
    if items.action == "default":
        return dicts
    if items.action == "update":
        if is_jsons:
            dicts["html"].update(items.html)
            dicts["update_time"] = str(datetime.datetime.now())
            return dicts
        return {"update_time": str(datetime.datetime.now()), "html": items.html}
    if items.action == "replace":
        return {"update_time": str(datetime.datetime.now()), "html": items.html}
    if items.action == "delete":
        return None


@router.post("/step1/journallist")
async def journal_list(input: InputInfoModel[SaveJournalIdModel]):
    """
    保存到大表
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    product = "CNKI"
    types = "3"
    step_name = "journallist"
    pages = input.data.page
    html = input.data.html
    ids = "_".join([product, types, step_name, pages])
    # step_info = MongoDBClient.db30_1.client.htmljson.step_info
    step_info = Coll.get_step_info()
    cjip = await step_info.find_one({"_id": ids})
    if cjip:
        dicts = SaveStepMongoModel[SaveJournalIdModel](step_info=SaveJournalIdModel()).parse_obj(cjip).dict()
        dicts["step_info"]["html"] = html
        dicts["update_time"] = str(datetime.datetime.now())
        save = SaveStepMongoModel[SaveJournalIdModel](step_info=SaveJournalIdModel()).parse_obj(dicts)
        result = await step_info.replace_one({'_id': ids}, save.dict(by_alias=True, exclude={"id"}))
    else:
        save = SaveStepMongoModel[SaveJournalIdModel](_id=ids, product=product, types=types,
                                                      step_name=step_name,
                                                      step_info=SaveJournalIdModel(page=pages, html=html),
                                                      update_time=str(datetime.datetime.now()),
                                                      create_time=str(datetime.datetime.now())
                                                      )
        result = await step_info.insert_one(save.dict(by_alias=True))
    return_info.status = SUCCESS
    return_info.msg_code = 200
    return_info.msg = "保存到mongodb成功"
    return_info.data = ""
    return return_info.todict()


@router.post("/step1/journallistsubject")
async def journal_list(input: InputInfoModel[SaveJournalSubjectModel]):
    """
    下载期刊列表 按照学科导航
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    product = "CNKI"
    types = "3"
    step_name = "journallistsubject"
    pages = input.data.page
    subject = input.data.subject
    html = input.data.html
    ids = "_".join([product, types, step_name, subject, pages])
    # step_info = MongoDBClient.db30_1.client.htmljson.step_info
    step_info = Coll.get_step_info()
    cjip = await step_info.find_one({"_id": ids})
    if cjip:
        dicts = SaveStepMongoModel[SaveJournalSubjectModel](step_info=SaveJournalSubjectModel()).parse_obj(cjip).dict()
        dicts["step_info"]["html"] = html
        dicts["update_time"] = str(datetime.datetime.now())
        save = SaveStepMongoModel[SaveJournalSubjectModel](step_info=SaveJournalSubjectModel()).parse_obj(dicts)
        result = await step_info.replace_one({'_id': ids}, save.dict(by_alias=True, exclude={"id"}))
    else:
        save = SaveStepMongoModel[SaveJournalSubjectModel](_id=ids, product=product, types=types,
                                                           step_name=step_name,
                                                           step_info=SaveJournalSubjectModel(page=pages,
                                                                                             subject=subject,
                                                                                             html=html),
                                                           update_time=str(datetime.datetime.now()),
                                                           create_time=str(datetime.datetime.now())
                                                           )
        result = await step_info.insert_one(save.dict(by_alias=True))
    return_info.status = SUCCESS
    return_info.msg_code = 200
    return_info.msg = "保存到mongodb成功"
    return_info.data = ""
    return return_info.todict()


@router.post("/step2/journalinfo")
async def journal_list(input: InputInfoModel[SaveYearModel]):
    """
    保存到大表
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    product = "CNKI"
    types = "3"
    step_name = "journalinfo"
    pykm = input.data.pykm
    html = input.data.html
    ids = "_".join([product, types, step_name, pykm])
    # step_info = MongoDBClient.db30_1.client.htmljson.step_info
    step_info = Coll.get_step_info()
    cjip = await step_info.find_one({"_id": ids})
    if cjip:
        dicts = SaveStepMongoModel[SaveYearModel](step_info=SaveYearModel()).parse_obj(cjip).dict()
        dicts["step_info"]["html"] = html
        dicts["step_info"]["pykm"] = pykm
        dicts["update_time"] = str(datetime.datetime.now())
        save = SaveStepMongoModel[SaveYearModel](step_info=SaveYearModel()).parse_obj(dicts)
        result = await step_info.replace_one({'_id': ids}, save.dict(by_alias=True, exclude={"id"}))
    else:
        save = SaveStepMongoModel[SaveYearModel](_id=ids, product=product, types=types,
                                                 step_name=step_name,
                                                 step_info=SaveYearModel(pykm=pykm, html=html),
                                                 update_time=str(datetime.datetime.now()),
                                                 create_time=str(datetime.datetime.now())
                                                 )
        result = await step_info.insert_one(save.dict(by_alias=True))
    return_info.status = SUCCESS
    return_info.msg_code = 200
    return_info.msg = "保存到mongodb成功"
    return_info.data = ""
    return return_info.todict()


@router.post("/step5/yearlist")
async def journal_list(input: InputInfoModel[SaveYearModel]):
    """
    保存到大表
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    product = "CNKI"
    types = "3"
    step_name = "yearlist"
    pykm = input.data.pykm
    html = input.data.html
    ids = "_".join([product, types, step_name, pykm])
    # step_info = MongoDBClient.db30_1.client.htmljson.step_info
    step_info = Coll.get_step_info()
    cjip = await step_info.find_one({"_id": ids})
    if cjip:
        dicts = SaveStepMongoModel[SaveYearModel](step_info=SaveYearModel()).parse_obj(cjip).dict()
        dicts["step_info"]["html"] = html
        dicts["step_info"]["pykm"] = pykm
        dicts["update_time"] = str(datetime.datetime.now())
        save = SaveStepMongoModel[SaveYearModel](step_info=SaveYearModel()).parse_obj(dicts)
        result = await step_info.replace_one({'_id': ids}, save.dict(by_alias=True, exclude={"id"}))
    else:
        save = SaveStepMongoModel[SaveYearModel](_id=ids, product=product, types=types,
                                                 step_name=step_name,
                                                 step_info=SaveYearModel(pykm=pykm, html=html),
                                                 update_time=str(datetime.datetime.now()),
                                                 create_time=str(datetime.datetime.now())
                                                 )
        result = await step_info.insert_one(save.dict(by_alias=True))
    return_info.status = SUCCESS
    return_info.msg_code = 200
    return_info.msg = "保存到mongodb成功"
    return_info.data = ""
    return return_info.todict()


@router.post("/step5/save_online")
async def journal_list(input: InputInfoModel[SaveOutlineModel]):
    """
    保存网络首发
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    product = "CNKI"
    types = "3"
    step_name = "outline"
    pykm = input.data.pykm
    pageindex = input.data.pageindex
    html = input.data.html
    ids = "_".join([product, types, step_name, pykm, pageindex])
    step_info = Coll.get_step_info()
    cjip = await step_info.find_one({"_id": ids})
    if cjip:
        dicts = SaveStepMongoModel[SaveOutlineModel](step_info=SaveOutlineModel()).parse_obj(cjip).dict()
        dicts["step_info"]["html"] = html
        dicts["step_info"]["pageindex"] = pageindex
        dicts["step_info"]["pykm"] = pykm
        dicts["update_time"] = str(datetime.datetime.now())
        save = SaveStepMongoModel[SaveOutlineModel](step_info=SaveOutlineModel()).parse_obj(dicts)
        result = await step_info.replace_one({'_id': ids}, save.dict(by_alias=True, exclude={"id"}))
    else:
        save = SaveStepMongoModel[SaveOutlineModel](_id=ids, product=product,
                                                    types=types,
                                                    step_name=step_name,
                                                    step_info=SaveOutlineModel(
                                                        pykm=pykm,
                                                        pageindex=pageindex,
                                                        html=html),
                                                    update_time=str(datetime.datetime.now()),
                                                    create_time=str(datetime.datetime.now())
                                                    )
        result = await step_info.insert_one(save.dict(by_alias=True))
    return_info.status = SUCCESS
    return_info.msg_code = 200
    return_info.msg = "保存到mongodb成功"
    return_info.data = ""
    return return_info.todict()


@router.post("/step5/is_have_online")
async def journal_list(input: InputInfoModel[SaveOutlineModel]):
    """
    保存网络首发
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    product = "CNKI"
    types = "3"
    step_name = "outline"
    pykm = input.data.pykm
    pageindex = input.data.pageindex
    ids = "_".join([product, types, step_name, pykm, pageindex])
    step_info = Coll.get_step_info()
    cjip = await step_info.find_one({"_id": ids})
    if cjip:
        update_time_s = str(BaseTime().get_day_before(datetime.datetime.now(), 3))
        if cjip["update_time"] > update_time_s:
            data = "true"
        else:
            data = "false"
    else:
        data = "false"
    return_info.status = SUCCESS
    return_info.msg_code = 200
    return_info.msg = "保存到mongodb成功"
    return_info.data = data
    return return_info.todict()


@router.post("/step7/issueinfo")
async def journal_list(input: InputInfoModel[SaveIssueModel]):
    """
    保存到大表
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    product = "CNKI"
    types = "3"
    step_name = "issueinfo"
    pykm = input.data.pykm
    pubyear = input.data.pubyear
    num = input.data.num
    pageIdx = input.data.page
    html = input.data.html
    ids = "_".join([product, types, step_name, pykm, pubyear, num, pageIdx])
    # step_info = MongoDBClient.db30_1.client.htmljson.step_info
    step_info = Coll.get_step_info()
    cjip = await step_info.find_one({"_id": ids})
    if cjip:
        dicts = SaveStepMongoModel[SaveIssueModel].parse_obj(cjip).dict()
        dicts["step_info"]["html"] = html
        dicts["step_info"]["pykm"] = pykm
        dicts["step_info"]["pubyear"] = pubyear
        dicts["step_info"]["num"] = num
        dicts["step_info"]["page"] = pageIdx
        dicts["update_time"] = str(datetime.datetime.now())
        save = SaveStepMongoModel[SaveIssueModel].parse_obj(dicts)
        result = await step_info.replace_one({'_id': ids}, save.dict(by_alias=True, exclude={"id"}))
    else:
        save = SaveStepMongoModel[SaveIssueModel](_id=ids, product=product, types=types,
                                                  step_name=step_name,
                                                  step_info=SaveIssueModel(pykm=pykm, html=html,
                                                                           pubyear=pubyear,
                                                                           num=num, page=pageIdx),
                                                  update_time=str(datetime.datetime.now()),
                                                  create_time=str(datetime.datetime.now())
                                                  )
        result = await step_info.insert_one(save.dict(by_alias=True))
    return_info.status = SUCCESS
    return_info.msg_code = 200
    return_info.msg = "保存到mongodb成功"
    return_info.data = ""
    return return_info.todict()


@router.post("/step8/artilceandref")
async def down_article(input: InputInfoModel[SaveHtmlModel]):
    """
    保存mongodb
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    dicts_default = {"update_time": str(datetime.datetime.now()), "html": ""}
    dicts_default_json = {"update_time": str(datetime.datetime.now()), "html": {}}

    try:
        # cnki_article_detail = MongoDBClient.db30_1.client.htmljson.cnki_article_detail_new
        cnki_article_detail = Coll.get_cnki_article_detail_new()
        cjip = await cnki_article_detail.find_one({"_id": input.data.filename})
        if cjip:
            # 要使用update，必须是dicts才有意义
            cjip["refdicts"] = deal(input.data.refhtml, cjip["refdicts"], is_jsons=True)
            cjip["article"] = deal(input.data.articlehtml, cjip["article"])
            cjip["oversea"] = deal(input.data.overseahtml, cjip["oversea"])
            cjip["refcount"] = deal(input.data.refcounthtml, cjip["refcount"], is_jsons=True)
            cjip["re_down_num"] = input.data.re_down_num
            cjip["redown"] = input.data.redown
            cjip["update_time"] = str(datetime.datetime.now())
            camm = CnkiArticleMongoModel.parse_obj(cjip)
            result = await cnki_article_detail.replace_one({'_id': input.data.filename}, camm.dict(by_alias=True))
        else:
            cjip = CnkiArticleMongoModel.parse_obj({})
            cjip.id = input.data.filename
            cjip.refdicts = deal(input.data.refhtml, dicts_default_json, is_jsons=True)
            cjip.article = deal(input.data.articlehtml, dicts_default)
            cjip.oversea = deal(input.data.overseahtml, dicts_default)
            cjip.refcount = deal(input.data.refcounthtml, dicts_default_json, is_jsons=True)
            cjip.redown = input.data.redown
            cjip.re_down_num = input.data.re_down_num
            cjip.update_time = str(datetime.datetime.now())
            cjip.create_time = str(datetime.datetime.now())
            camm = CnkiArticleMongoModel.parse_obj(cjip.dict(by_alias=True))
            result = await cnki_article_detail.insert_one(camm.dict(by_alias=True))
        return_info.status = SUCCESS
        return_info.msg_code = 200
        return_info.msg = "保存到mongodb成功"
        return_info.data = ""
        return return_info.todict()
    except Exception as e:

        return_info.status = FAILED
        return_info.msg_code = MsgCode.MONGO_ERROR
        return_info.msg = "保存到mongodb失败"
        return_info.data = {"err": traceback.format_exc()}
        return return_info.todict()


@router.post("/step8/save_online_article")
async def journal_list(input: InputInfoModel[SaveOnlineArticleModel]):
    """
    保存文章
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    task_name = "cnkionline"
    step_name = "article"
    html = input.data.html
    html_oversea = input.data.html_oversea
    filename = input.data.filename
    ids = input.data.id

    id_ = "_".join([task_name, step_name, ids])
    other = Coll.get_other()
    cjip = await other.find_one({"_id": id_})
    down_date = str(datetime.datetime.now())
    if cjip:
        dicts = DetailModel[SaveOnlineArticleModel].parse_obj(cjip).dict()
        dicts["step_info"]["html"] = html
        dicts["step_info"]["html_oversea"] = html_oversea
        dicts["step_info"]["filename"] = filename
        dicts["update_time"] = str(datetime.datetime.now())
        dicts["down_date"] = down_date
        save = DetailModel[SaveOnlineArticleModel].parse_obj(dicts)
        result = await other.replace_one({'_id': id_}, save.dict(by_alias=True, exclude={"id"}))
    else:
        save = DetailModel[SaveOnlineArticleModel](
            _id=id_,
            task_name=task_name,
            step_name=step_name,
            step_info=SaveOnlineArticleModel(
                id=ids,
                html=html,
                html_oversea=html_oversea,
                filename=filename
            ),
            downdate=down_date,
            update_time=str(datetime.datetime.now()),
            create_time=str(datetime.datetime.now())
        )
        result = await other.insert_one(save.dict(by_alias=True))
    return_info.status = SUCCESS
    return_info.msg_code = 200
    return_info.msg = "保存到mongodb成功"
    return_info.data = ""
    return return_info.todict()


@router.post("/step8/artilceandrefredown")
async def down_article(input: InputInfoModel[SaveHtmlModel]):
    """
    保存mongodb
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    dicts_default = {"update_time": str(datetime.datetime.now()), "html": ""}
    dicts_default_json = {"update_time": str(datetime.datetime.now()), "html": {}}

    try:
        # cnki_article_detail = MongoDBClient.db30_1.client.htmljson.cnki_article_detail_new
        cnki_article_detail = Coll.get_cnki_article_detail_new()
        cjip = await cnki_article_detail.find_one({"_id": input.data.filename})

        if cjip:
            # 如果 mongodb原来的redown有数据
            if cjip["redown"]["re_down_num"] != "0":
                # 如果新的数据和原来的下载不是一个redown
                if str(input.data.redown.re_down_num) != str(cjip["redown"]["re_down_num"]):
                    cjip.update(copy.deepcopy(cjip["redown"]))
                    cjip["redown"] = {}
                    cjip["redown"]["re_down_num"] = input.data.redown.re_down_num
                    # 要使用update，必须是dicts才有意义
                    cjip["redown"]["refdicts"] = deal(input.data.redown.refhtml, dicts_default_json,
                                                      is_jsons=True)
                    cjip["redown"]["article"] = deal(input.data.redown.articlehtml, dicts_default)
                    cjip["redown"]["oversea"] = deal(input.data.redown.overseahtml, dicts_default)
                    cjip["redown"]["refcount"] = deal(input.data.redown.refcounthtml, dicts_default_json,
                                                      is_jsons=True)
                else:
                    # 如果一样代表更新而不是重新下载
                    cjip["redown"]["refdicts"] = deal(input.data.redown.refhtml, cjip["redown"]["refdicts"],
                                                      is_jsons=True)
                    cjip["redown"]["article"] = deal(input.data.redown.articlehtml, cjip["redown"]["article"])
                    cjip["redown"]["oversea"] = deal(input.data.redown.overseahtml, cjip["redown"]["oversea"])
                    cjip["redown"]["refcount"] = deal(input.data.redown.refcounthtml, cjip["redown"]["refcount"],
                                                      is_jsons=True)
            else:
                # 代表redown里没有数据
                cjip["redown"]["re_down_num"] = input.data.redown.re_down_num
                cjip["redown"]["refdicts"] = deal(input.data.redown.refhtml, dicts_default_json, is_jsons=True)
                cjip["redown"]["article"] = deal(input.data.redown.articlehtml, dicts_default)
                cjip["redown"]["oversea"] = deal(input.data.redown.overseahtml, dicts_default)
                cjip["redown"]["refcount"] = deal(input.data.redown.refcounthtml, dicts_default_json, is_jsons=True)

            cjip["update_time"] = str(datetime.datetime.now())

            camm = CnkiArticleMongoModel.parse_obj(cjip)
            result = await cnki_article_detail.replace_one({'_id': input.data.filename}, camm.dict(by_alias=True))
        else:
            # 代表完全没有这条数据
            cjip = {}
            cjip["_id"] = input.data.filename
            cjip["refdicts"] = deal(input.data.refhtml, dicts_default_json, is_jsons=True)
            cjip["article"] = deal(input.data.articlehtml, dicts_default)
            cjip["oversea"] = deal(input.data.overseahtml, dicts_default)
            cjip["refcount"] = deal(input.data.refcounthtml, dicts_default_json, is_jsons=True)
            cjip["redown"] = {}
            cjip["redown"]["re_down_num"] = input.data.redown.re_down_num
            cjip["redown"]["refdicts"] = deal(input.data.redown.refhtml, dicts_default_json, is_jsons=True)
            cjip["redown"]["article"] = deal(input.data.redown.articlehtml, dicts_default)
            cjip["redown"]["oversea"] = deal(input.data.redown.overseahtml, dicts_default)
            cjip["redown"]["refcount"] = deal(input.data.redown.refcounthtml, dicts_default_json, is_jsons=True)

            cjip["update_time"] = str(datetime.datetime.now())
            cjip["create_time"] = str(datetime.datetime.now())

            camm = CnkiArticleMongoModel.parse_obj(cjip)
            result = await cnki_article_detail.insert_one(camm.dict(by_alias=True))
        return_info.status = SUCCESS
        return_info.msg_code = 200
        return_info.msg = "保存到mongodb成功"
        return_info.data = ""
        return return_info.todict()
    except Exception as e:
        return_info.status = FAILED
        return_info.msg_code = MsgCode.MONGO_ERROR
        return_info.msg = "保存到mongodb失败"
        return_info.data = {"err": traceback.print_exc()}
        return return_info.todict()


@router.post("/verification/ver_article")
async def verification_ref(input: InputInfoModel[VerificationMongodb]):
    """
    验证article 是否正确
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    filename = input.data.filename
    # cnki_article_detail = MongoDBClient.db30_1.client.htmljson.cnki_article_detail_new
    cnki_article_detail = Coll.get_cnki_article_detail_new()
    cjip = await cnki_article_detail.find_one({"_id": filename})
    if cjip:
        camm = CnkiArticleMongoModel.parse_obj(cjip)

        if camm.redown.re_down_num == "0":
            redown = "false"
            temp = camm
        else:
            redown = "true"
            temp = camm.redown
        try:
            refcount = temp.refcount.html["REFERENCE"]
        except:
            return_info.status = FAILED
            return_info.msg_code = 200
            return_info.msg = "refcount 不存在,结构错误"
            return return_info.todict()
        try:
            refhtml = temp.refdicts.html["first"]
        except:
            refhtml = ""
        if str(refcount) == "0":
            temp.refdicts = MongoJsonModel()
            ref_stat = "true"
        else:
            xpath_dicts = {
                'pcount': '//span[@name="pcount"]/text()',
            }
            mc = MParsel()
            bools, new_dict = mc.xpath_parsel_html(refhtml, xpath_selector=xpath_dicts)
            allcount = 0
            if bools:
                for item in new_dict["pcount"]:
                    allcount = allcount + int(item)
            reftime = str(temp.refdicts.update_time).split(" ")[0]
            refcounttime = str(temp.refcount.update_time).split(" ")[0]
            if (str(allcount) == str(refcount) or reftime == refcounttime) and temp.refdicts.html != {}:
                ref_stat = "true"
                for k, v in temp.refdicts.html.items():
                    if v == "":
                        ref_stat = "false"
            else:
                temp.refdicts = MongoJsonModel()
                ref_stat = "false"
        marks = input.data.marks
        try:
            article = temp.article.html
            rrq = AioHttpRequest()
            rrq.set_marks(marks).set_html(article).set_middler_list(
                [rrq.have_end_middlerwares, rrq.marks_middlerwares])
            bools, dicts = rrq.all_middlerwares({})
            if bools:
                article = "true"
            else:
                temp.article = MongoHtmlModel()
                article = "false"
        except:
            temp.article = MongoHtmlModel()
            article = "false"
        marks_oversea = input.data.marks_oversea
        try:
            oversea = temp.oversea.html
            rrq = AioHttpRequest()
            rrq.set_marks(marks_oversea).set_html(oversea).set_middler_list(
                [rrq.have_end_middlerwares, rrq.marks_middlerwares])

            bools, dicts = rrq.all_middlerwares({})
            if bools:
                oversea = "true"
            else:
                temp.oversea = MongoHtmlModel()
                oversea = "false"
        except:
            temp.oversea = MongoHtmlModel()
            oversea = "false"

        camm = CnkiArticleMongoModel.parse_obj(cjip)
        result = await cnki_article_detail.replace_one({'_id': filename}, camm.dict(by_alias=True))

        return_info.data = {"redown": redown, "ref_stat": ref_stat, "article": article, "oversea": oversea}
        return_info.status = SUCCESS
        return_info.msg_code = 200
    else:
        return_info.status = FAILED
        return_info.msg_code = 200
        return_info.msg = "filename 不存在"
    return return_info.todict()
